#include "Item_Word.h"
#include "Log.h"

unsigned int edit_distance( const std::string& s1,
                            const std::string& s2 );

void Item_Word::parse(Parser& parser,
                      const Metadata& fInfo,
                      std::string& name) {
    LOG_ENTER(OBJECT,"Item_Word::parse");

    parser.next_ine();
    parser.match_any_word(word);
    name = word;

    LOG_EXIT();
}

std::ostream& Item_Word::print(std::ostream& os) const {
    LOG_ENTER(OBJECT,"Item_Word::print");

    os << std::string("[ ");
    os << word;
    os << std::string(" ]");

    LOG_EXIT();
    return os;
}

bool Item_Word::operator==(const Metric_Object *other) const {
    LOG_ENTER(OBJECT,"Item_Word::operator==");

    LOG_EXIT();
    return word == ((Item_Word *)other)->word;
}

double Item_Word::metric(const Metric_Object *other) const {
    LOG_ENTER(OBJECT,"Item_Word::distance");

    double result = edit_distance(word, ((Item_Word*)other)->word);

    LOG_EXIT();
    return result;
}

std::ostream& operator<<( std::ostream& os,
                          const Item_Word& w ) {
    LOG_ENTER(OBJECT,"operator<<");

    LOG_EXIT();
    return w.print(os);
}

unsigned int edit_distance( const std::string& s1, const std::string& s2 )
{
    const unsigned int cost_del = 1;
    const unsigned int cost_ins = 1;
    const unsigned int cost_sub = 1;

    unsigned int n1 = s1.length();
    unsigned int n2 = s2.length();

    unsigned int* p = new unsigned int[n2+1];
    unsigned int* q = new unsigned int[n2+1];
    unsigned int* r;

    p[0] = 0;
    for( unsigned int j = 1; j <= n2; ++j )
        p[j] = p[j-1] + cost_ins;

    for( unsigned int i = 1; i <= n1; ++i )
    {
        q[0] = p[0] + cost_del;
        for( unsigned int j = 1; j <= n2; ++j )
        {
            unsigned int d_del = p[j] + cost_del;
            unsigned int d_ins = q[j-1] + cost_ins;
            unsigned int d_sub = p[j-1] + ( s1[i-1] == s2[j-1] ? 0 : cost_sub );
            q[j] = std::min( std::min( d_del, d_ins ), d_sub );
        }
        r = p;
        p = q;
        q = r;
    }

    unsigned int tmp = p[n2];
    delete[] p;
    delete[] q;

    return tmp;
}
